Adds a new mode - check - which only checks code, rather than generating machine code. It takes into account that proc macros and build scripts will still require generated code.
Implemented by adding a check profile and setting this on each Unit, unless the unit is required to be built (i.e., is a proc macro, build script, or dep of one).
Some common cargo commands are (see all commands with --list):
build Compile the current project
+ check Analyze the current project and report errors, but don't build object files
clean Remove the target directory
doc Build this project's and its dependencies' documentation
new Create a new cargo project
($mac:ident) => {
$mac!(bench);
$mac!(build);
+ $mac!(check);
$mac!(clean);
$mac!(doc);
$mac!(fetch);
--- /dev/null
+use std::env;
+
+use cargo::core::Workspace;
+use cargo::ops::{self, CompileOptions, MessageFormat};
+use cargo::util::important_paths::{find_root_manifest_for_wd};
+use cargo::util::{CliResult, Config};
+
+#[derive(RustcDecodable)]
+pub struct Options {
+ flag_package: Vec<String>,
+ flag_jobs: Option<u32>,
+ flag_features: Vec<String>,
+ flag_all_features: bool,
+ flag_no_default_features: bool,
+ flag_target: Option<String>,
+ flag_manifest_path: Option<String>,
+ flag_verbose: u32,
+ flag_quiet: Option<bool>,
+ flag_color: Option<String>,
+ flag_message_format: MessageFormat,
+ flag_release: bool,
+ flag_lib: bool,
+ flag_bin: Vec<String>,
+ flag_example: Vec<String>,
+ flag_test: Vec<String>,
+ flag_bench: Vec<String>,
+ flag_locked: bool,
+ flag_frozen: bool,
+}
+
+pub const USAGE: &'static str = "
+Check a local package and all of its dependencies for errors
+
+Usage:
+ cargo check [options]
+
+Options:
+ -h, --help Print this message
+ -p SPEC, --package SPEC ... Package to check
+ -j N, --jobs N Number of parallel jobs, defaults to # of CPUs
+ --lib Check only this package's library
+ --bin NAME Check only the specified binary
+ --example NAME Check only the specified example
+ --test NAME Check only the specified test target
+ --bench NAME Check only the specified benchmark target
+ --release Check artifacts in release mode, with optimizations
+ --features FEATURES Space-separated list of features to also check
+ --all-features Check all available features
+ --no-default-features Do not check the `default` feature
+ --target TRIPLE Check for the target triple
+ --manifest-path PATH Path to the manifest to compile
+ -v, --verbose ... Use verbose output
+ -q, --quiet No output printed to stdout
+ --color WHEN Coloring: auto, always, never
+ --message-format FMT Error format: human, json [default: human]
+ --frozen Require Cargo.lock and cache are up to date
+ --locked Require Cargo.lock is up to date
+
+If the --package argument is given, then SPEC is a package id specification
+which indicates which package should be built. If it is not given, then the
+current package is built. For more information on SPEC and its format, see the
+`cargo help pkgid` command.
+
+Compilation can be configured via the use of profiles which are configured in
+the manifest. The default profile for this command is `dev`, but passing
+the --release flag will use the `release` profile instead.
+";
+
+pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
+ debug!("executing; cmd=cargo-check; args={:?}",
+ env::args().collect::<Vec<_>>());
+ config.configure(options.flag_verbose,
+ options.flag_quiet,
+ &options.flag_color,
+ options.flag_frozen,
+ options.flag_locked)?;
+
+ let root = find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())?;
+
+ let opts = CompileOptions {
+ config: config,
+ jobs: options.flag_jobs,
+ target: options.flag_target.as_ref().map(|t| &t[..]),
+ features: &options.flag_features,
+ all_features: options.flag_all_features,
+ no_default_features: options.flag_no_default_features,
+ spec: &options.flag_package,
+ mode: ops::CompileMode::Check,
+ release: options.flag_release,
+ filter: ops::CompileFilter::new(options.flag_lib,
+ &options.flag_bin,
+ &options.flag_test,
+ &options.flag_example,
+ &options.flag_bench),
+ message_format: options.flag_message_format,
+ target_rustdoc_args: None,
+ target_rustc_args: None,
+ };
+
+ let ws = Workspace::new(&root, config)?;
+ ops::compile(&ws, &opts)?;
+ Ok(None)
+}
"lib" => LibKind::Lib,
"rlib" => LibKind::Rlib,
"dylib" => LibKind::Dylib,
- "procc-macro" => LibKind::ProcMacro,
+ "proc-macro" => LibKind::ProcMacro,
s => LibKind::Other(s.to_string()),
}
}
pub test: bool,
pub doc: bool,
pub run_custom_build: bool,
+ pub check: bool,
pub panic: Option<String>,
}
pub bench_deps: Profile,
pub doc: Profile,
pub custom_build: Profile,
+ pub check: Profile,
}
/// Information about a binary, a library, an example, etc. that is part of the
..Profile::default_dev()
}
}
+
+ pub fn default_check() -> Profile {
+ Profile {
+ check: true,
+ ..Profile::default_dev()
+ }
+ }
}
impl Default for Profile {
test: false,
doc: false,
run_custom_build: false,
+ check: false,
panic: None,
}
}
write!(f, "Profile(doc)")
} else if self.run_custom_build {
write!(f, "Profile(run)")
+ } else if self.check {
+ write!(f, "Profile(check)")
} else {
write!(f, "Profile(build)")
}
bench_deps: Profile::default_release(),
doc: Profile::default_doc(),
custom_build: Profile::default_custom_build(),
+ check: Profile::default_check(),
};
for pkg in self.members().filter(|p| p.manifest_path() != root_manifest) {
for kind in [Kind::Host, Kind::Target].iter() {
let Profiles {
ref release, ref dev, ref test, ref bench, ref doc,
- ref custom_build, ref test_deps, ref bench_deps,
+ ref custom_build, ref test_deps, ref bench_deps, ref check
} = *profiles;
let profiles = [release, dev, test, bench, doc, custom_build,
- test_deps, bench_deps];
+ test_deps, bench_deps, check];
for profile in profiles.iter() {
units.push(Unit {
pkg: &pkg,
pub enum CompileMode {
Test,
Build,
+ Check,
Bench,
Doc { deps: bool },
}
let profiles = ws.profiles();
- let resolve = resolve_dependencies(ws,
- source,
- features,
- all_features,
- no_default_features,
- &spec)?;
- let (spec, packages, resolve_with_overrides) = resolve;
+ let pair = resolve_dependencies(ws,
+ source,
+ features,
+ all_features,
+ no_default_features,
+ &specs)?;
+ let (packages, resolve_with_overrides) = pair;
let mut pkgids = Vec::new();
if spec.len() > 0 {
CompileMode::Test => test,
CompileMode::Bench => &profiles.bench,
CompileMode::Build => build,
+ CompileMode::Check => &profiles.check,
CompileMode::Doc { .. } => &profiles.doc,
};
match *filter {
}
Ok(base)
}
- CompileMode::Build => {
+ CompileMode::Build | CompileMode::Check => {
Ok(pkg.targets().iter().filter(|t| {
t.is_bin() || t.is_lib()
}).map(|t| (t, profile)).collect())
use super::links::Links;
use super::{Kind, Compilation, BuildConfig};
-#[derive(Clone, Copy, Eq, PartialEq, Hash)]
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub struct Unit<'a> {
pub pkg: &'a Package,
pub target: &'a Target,
let dest = if build_config.release { "release" } else { "debug" };
let host_layout = Layout::new(ws, None, &dest)?;
let target_layout = match build_config.requested_target.as_ref() {
- Some(target) => {
- Some(Layout::new(ws, Some(&target), &dest)?)
- }
+ Some(target) => Some(Layout::new(ws, Some(&target), dest)?),
None => None,
};
unit: &Unit<'a>,
crate_types: &mut BTreeSet<String>)
-> CargoResult<()> {
+ if unit.profile.check {
+ crate_types.insert("metadata".to_string());
+ }
for target in unit.pkg.manifest().targets() {
crate_types.extend(target.rustc_crate_types().iter().map(|s| {
if *s == "lib" {
line.contains(crate_type)
});
if not_supported {
+ if crate_type == "metadata" {
+ bail!("compiler does not support `--crate-type metadata`, \
+ cannot run `cargo check`.");
+ }
map.insert(crate_type.to_string(), None);
continue
}
let mut visited = HashSet::new();
for unit in units {
self.walk_used_in_plugin_map(unit,
- unit.target.for_host(),
- &mut visited)?;
+ unit.target.for_host(),
+ &mut visited)?;
}
Ok(())
}
}
for unit in self.dep_targets(unit)? {
self.walk_used_in_plugin_map(&unit,
- is_plugin || unit.target.for_host(),
- visited)?;
+ is_plugin || unit.target.for_host(),
+ visited)?;
}
Ok(())
}
}
}
};
- match *unit.target.kind() {
- TargetKind::Example |
- TargetKind::Bin |
- TargetKind::CustomBuild |
- TargetKind::Bench |
- TargetKind::Test => {
- add("bin", false)?;
- }
- TargetKind::Lib(..) if unit.profile.test => {
- add("bin", false)?;
- }
- TargetKind::Lib(ref libs) => {
- for lib in libs {
- add(lib.crate_type(), lib.linkable())?;
+
+ if unit.profile.check {
+ add("metadata", true)?;
+ } else {
+ match *unit.target.kind() {
+ TargetKind::Example |
+ TargetKind::Bin |
+ TargetKind::CustomBuild |
+ TargetKind::Bench |
+ TargetKind::Test => {
+ add("bin", false)?;
+ }
+ TargetKind::Lib(..) if unit.profile.test => {
+ add("bin", false)?;
+ }
+ TargetKind::Lib(ref libs) => {
+ for lib in libs {
+ add(lib.crate_type(), lib.linkable())?;
+ }
}
}
}
match self.get_package(id) {
Ok(pkg) => {
pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
- Ok(Unit {
+ let profile = if unit.profile.check &&
+ !t.is_custom_build()
+ && !t.for_host() {
+ &self.profiles.check
+ } else {
+ self.lib_profile()
+ };
+ let unit = Unit {
pkg: pkg,
target: t,
- profile: self.lib_profile(),
+ profile: profile,
kind: unit.kind.for_target(t),
- })
+ };
+ Ok(unit)
})
}
Err(e) => Some(Err(e))
pub overrides: HashMap<String, BuildOutput>,
}
-pub type PackagesToBuild<'a> = [(&'a Package, Vec<(&'a Target,&'a Profile)>)];
+pub type PackagesToBuild<'a> = [(&'a Package, Vec<(&'a Target, &'a Profile)>)];
// Returns a mapping of the root package plus its immediate dependencies to
// where the compiled libraries are all located.
for unit in cx.dep_targets(unit)?.iter() {
compile(cx, jobs, unit)?;
}
+
Ok(())
}
// FIXME(rust-lang/rust#18913): we probably shouldn't have to do
// this manually
- for &(ref dst, ref _link_dst, _linkable) in filenames.iter() {
- if fs::metadata(&dst).is_ok() {
- fs::remove_file(&dst).chain_error(|| {
- human(format!("Could not remove file: {}.", dst.display()))
- })?;
+ for &(ref filename, ref _link_dst, _linkable) in filenames.iter() {
+ let mut dsts = vec![root.join(filename)];
+ // If there is both an rmeta and rlib, rustc will prefer to use the
+ // rlib, even if it is older. Therefore, we must delete the rlib to
+ // force using the new rmeta.
+ if dsts[0].extension() == Some(&OsStr::new("rmeta")) {
+ dsts.push(root.join(filename).with_extension("rlib"));
+ }
+ for dst in &dsts {
+ if fs::metadata(dst).is_ok() {
+ fs::remove_file(dst).chain_error(|| {
+ human(format!("Could not remove file: {}.", dst.display()))
+ })?;
+ }
}
}
let Profile {
ref opt_level, lto, codegen_units, ref rustc_args, debuginfo,
debug_assertions, rpath, test, doc: _doc, run_custom_build,
- ref panic, rustdoc_args: _,
+ ref panic, rustdoc_args: _, check,
} = *unit.profile;
assert!(!run_custom_build);
cmd.arg("--error-format").arg("json");
}
- if !test {
+ if check {
+ cmd.arg("--crate-type").arg("metadata");
+ } else if !test {
for crate_type in crate_types.iter() {
cmd.arg("--crate-type").arg(crate_type);
}
doc: merge(Profile::default_doc(),
profiles.and_then(|p| p.doc.as_ref())),
custom_build: Profile::default_custom_build(),
+ check: merge(Profile::default_check(),
+ profiles.and_then(|p| p.dev.as_ref())),
};
// The test/bench targets cannot have panic=abort because they'll all get
// compiled with --test which requires the unwind runtime currently
test: profile.test,
doc: profile.doc,
run_custom_build: profile.run_custom_build,
+ check: profile.check,
panic: panic.clone().or(profile.panic),
}
}
'--color=:colorization option:(auto always never)' \
;;
+ check)
+ _arguments \
+ '--features=[space separated feature list]' \
+ '--all-features[enable all available features]' \
+ '(-h, --help)'{-h,--help}'[show help message]' \
+ '(-j, --jobs)'{-j,--jobs}'[number of parallel jobs, defaults to # of CPUs]' \
+ "${command_scope_spec[@]}" \
+ '--manifest-path=[path to manifest]: :_files -/' \
+ '--no-default-features[do not check the default features]' \
+ '(-p,--package)'{-p=,--package=}'[package to check]:packages:_get_package_names' \
+ '--release=[check in release mode]' \
+ '--target=[target triple]' \
+ '(-v, --verbose)'{-v,--verbose}'[use verbose output]' \
+ '(-q, --quiet)'{-q,--quiet}'[no output printed to stdout]' \
+ '--color=:colorization option:(auto always never)' \
+ ;;
+
clean)
_arguments \
'(-h, --help)'{-h,--help}'[show help message]' \
local -a commands;commands=(
'bench:execute all benchmarks of a local package'
'build:compile the current project'
+'check:check the current project without compiling'
'clean:remove generated artifacts'
'doc:build package documentation'
'fetch:fetch package dependencies'
local opt___nocmd="$opt_common -V --version --list"
local opt__bench="$opt_common $opt_pkg $opt_feat $opt_mani $opt_jobs --target --lib --bin --test --bench --example --no-run"
local opt__build="$opt_common $opt_pkg $opt_feat $opt_mani $opt_jobs --target --lib --bin --test --bench --example --release"
+ local opt__check="$opt_common $opt_pkg $opt_feat $opt_mani $opt_jobs --target --lib --bin --example"
local opt__clean="$opt_common $opt_pkg $opt_mani --target --release"
local opt__doc="$opt_common $opt_pkg $opt_feat $opt_mani $opt_jobs --target --open --no-deps --release"
local opt__fetch="$opt_common $opt_mani"
--- /dev/null
+.TH "CARGO\-CHECK" "1" "May 2016" "The Rust package manager" "Cargo Manual"
+.hy
+.SH NAME
+.PP
+cargo\-check \- Check the current project
+.SH SYNOPSIS
+.PP
+\f[I]cargo check\f[] [OPTIONS]
+.SH DESCRIPTION
+.PP
+Check a local package and all of its dependencies.
+.PP
+If the \f[B]\-\-package\f[] argument is given, then \f[I]SPEC\f[] is a
+package id specification which indicates which package should be checked.
+If it is not given, then the current package is checked.
+For more information on \f[I]SPEC\f[] and its format, see the "cargo
+help pkgid" command.
+.PP
+Compilation can be configured via the use of profiles which are
+configured in the manifest.
+The default profile for this command is \f[I]dev\f[], but passing the
+\f[B]\-\-release\f[] flag will use the \f[I]release\f[] profile instead.
+.SH OPTIONS
+.TP
+.B \-h, \-\-help
+Print this message.
+.RS
+.RE
+.TP
+.B \-p \f[I]SPEC\f[], \-\-package \f[I]SPEC ...\f[]
+Package to check.
+.RS
+.RE
+.TP
+.B \-j \f[I]IN\f[], \-\-jobs \f[I]IN\f[]
+Number of parallel jobs, defaults to # of CPUs.
+.RS
+.RE
+.TP
+.B \-\-lib
+Check only this package\[aq]s library.
+.RS
+.RE
+.TP
+.B \-\-bin \f[I]NAME\f[]
+Check only the specified binary.
+.RS
+.RE
+.TP
+.B \-\-example \f[I]NAME\f[]
+Check only the specified example.
+.RS
+.RE
+.TP
+.B \-\-test \f[I]NAME\f[]
+Check only the specified test target.
+.RS
+.RE
+.TP
+.B \-\-bench \f[I]NAME\f[]
+Check only the specified benchmark target.
+.RS
+.RE
+.TP
+.B \-\-release
+Check artifacts in release mode.
+.RS
+.RE
+.TP
+.B \-\-all\-features
+Check with all available features.
+.RS
+.RE
+.TP
+.B \-\-features \f[I]FEATURES\f[]
+Space\-separated list of features to also check.
+.RS
+.RE
+.TP
+.B \-\-no\-default\-features
+Do not check the \f[C]default\f[] feature.
+.RS
+.RE
+.TP
+.B \-\-target \f[I]TRIPLE\f[]
+Check for the target triple.
+.RS
+.RE
+.TP
+.B \-\-manifest\-path \f[I]PATH\f[]
+Path to the manifest to compile.
+.RS
+.RE
+.TP
+.B \-v, \-\-verbose
+Use verbose output.
+.RS
+.RE
+.TP
+.B \-q, \-\-quiet
+No output printed to stdout.
+.RS
+.RE
+.TP
+.B \-\-color \f[I]WHEN\f[]
+Coloring: auto, always, never.
+.RS
+.RE
+.SH EXAMPLES
+.PP
+Check a local package and all of its dependencies
+.IP
+.nf
+\f[C]
+$\ cargo\ check
+\f[]
+.fi
+.PP
+Check a package with optimizations
+.IP
+.nf
+\f[C]
+$\ cargo\ check\ \-\-release
+\f[]
+.fi
+.SH SEE ALSO
+.PP
+cargo(1)
+.SH COPYRIGHT
+.PP
+This work is dual\-licensed under Apache 2.0 and MIT terms.
+See \f[I]COPYRIGHT\f[] file in the cargo source distribution.